# -*- coding: utf-8 -*-
# created on 2016/04/28

from sympy import FiniteSet, EmptySet
from mathsolver.functions.hanshu.zhiyu import HanShuZhiYu
from mathsolver.functions.base import BaseFunction, BaseEq, BaseVariable, BaseSymbolValue, new_latex
from mathsolver.functions.hanshu.helper import check_func, check_inter, cal_canshu_from_expr, yizhizhiyu_qiufanwei
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaSolve


class LingDianCunZaiQiuCanZ(BaseFunction):
    """区间上存在零点求参数 - 值域法"""

    def solver(self, *args):
        func, interval = check_func(args[0]), check_inter(args[1])
        expr, var = func.expression, func.var
        canshu = cal_canshu_from_expr(expr)

        # 求函数值域
        zhiyu_solver = HanShuZhiYu().solver(func, interval)
        self.steps.extend(zhiyu_solver.steps)
        zhiyu = zhiyu_solver.output[0].value

        self.steps.append(["", "由题意知 0 在值域内"])
        # 含参数 {canshu_range: range, ... }
        if isinstance(zhiyu, dict):
            canshu_ranges = EmptySet()
            for canshu_range, zhiyu_piece in zhiyu.items():
                piece_fanwei = yizhizhiyu_qiufanwei(0, zhiyu_piece)
                canshu_ranges = canshu_ranges.union(piece_fanwei.intersect(canshu_range))
        # 不含参数 range
        else:
            canshu_ranges = yizhizhiyu_qiufanwei(0, zhiyu)

        self.steps.append(["", "求得参数 %s 的取值范围是 %s" % (new_latex(canshu), new_latex(canshu_ranges))])
        self.output.append(BaseSymbolValue({canshu: canshu_ranges}))
        self.label.add("区间上存在零点求参数")
        return self


class LingDianCunZaiQiuCanM(BaseFunction):
    """区间上存在零点求参数 - Mathematica 解方程法"""

    def solver(self, *args):
        func, interval = check_func(args[0]), check_inter(args[1])
        expr, var = func.expression, func.var
        canshu = cal_canshu_from_expr(expr)

        math_solver = MathematicaSolve().solver(
            BaseEq([expr, 0]), BaseVariable([var]), {var: interval}).output[0].value

        # 找出参数范围
        canshu_ranges = EmptySet()
        # {m: {0}, (m, x): {((-oo, 0), -2), ((0, oo), -2)}, x: {0}}
        for prmt, vlus in math_solver.items():
            if isinstance(prmt, tuple):  # (m, x): {((-oo, 0), -2), ((0, oo), -2)} 格式
                for vlu in vlus:
                    parmt_vlu = dict(zip(prmt, vlu))
                    canshu_range = parmt_vlu[canshu]  # 区间 / 值
                    if canshu_range.is_Number:
                        canshu_range = FiniteSet(canshu_range)
                    canshu_ranges = canshu_ranges.union(canshu_range)
            elif prmt != canshu:  # x: {x0, x1, ...}
                continue
            else:  # m 是一个或多个值
                canshu_ranges = canshu_ranges.union(vlus)

        self.steps.append(["", "参数 %s 的取值范围是 %s" % (new_latex(canshu), new_latex(canshu_ranges))])
        self.output.append(BaseSymbolValue({canshu: canshu_ranges}))
        self.label.add("区间上存在零点求参数")
        return self


class LingDianCunZaiQiuCan(BaseFunction):
    """区间上存在零点求参数 - 值域法 + Mathematica 解方程法"""

    def solver(self, *args):
        clss = [LingDianCunZaiQiuCanZ, LingDianCunZaiQiuCanM]
        for cls in clss:
            try:
                return cls().solver(*args)
            except Exception:
                continue
        raise RuntimeError("cannot solve problem")


if __name__ == '__main__':
    pass
